package org.dromara.workflow.flowable;

import org.flowable.bpmn.model.AssociationDirection;
import org.flowable.image.impl.DefaultProcessDiagramCanvas;

import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;

/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：提供一个扩展点，以满足特定的流程图绘制需求
 */
/**
 * CustomDefaultProcessDiagramCanvas 类继承自 DefaultProcessDiagramCanvas，用于实现自定义的流程图画布
 * 该类旨在提供额外的功能或覆盖默认行为，以满足特定的绘图需求
 * 原始的 DefaultProcessDiagramCanvas 类可能不完全符合特定应用场景，因此通过继承进行扩展
 */
public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {

    /**
     * 设置高亮线的颜色  这里我设置成绿色
     */
    protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;

    /**
     * 构造函数：自定义流程图画布
     * 本构造函数用于初始化一个自定义的流程图画布对象，设置画布的基本属性，如尺寸、坐标、图像类型以及字体信息
     *
     * @param width          画布的宽度
     * @param height         画布的高度
     * @param minX           画布的最小X坐标
     * @param minY           画布的最小Y坐标
     * @param imageType      画布的图像类型，如"png"、"jpg"等
     * @param activityFontName  活动字体的名称
     * @param labelFontName    标签字体的名称
     * @param annotationFontName 注释字体的名称
     * @param customClassLoader 自定义的类加载器，用于加载外部资源
     * 通过这些参数，可以灵活定义画布的外观和行为，满足不同场景下的绘图需求
     */
    public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
        super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
    }

    /**
     * 画线颜色设置
     * 绘制连接线，支持不同的连线类型和条件，并可根据需求绘制默认流或高亮的连线
     *
     * @param xPoints 一组表示连接线上的点的x坐标
     * @param yPoints 一组表示连接线上的点的y坐标
     * @param conditional 是否为条件流
     * @param isDefault 是否为默认流
     * @param connectionType 连接线类型，如"association"
     * @param associationDirection 连接的方向，可以是ONE（单向）或BOTH（双向）
     * @param highLighted 是否高亮显示
     * @param scaleFactor 缩放系数，用于根据图形的显示比例调整箭头等元素的大小
     */
    public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
                               AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {

        // 保存原始的画笔和笔划样式
        Paint originalPaint = g.getPaint();
        Stroke originalStroke = g.getStroke();

        // 设置连接线的基本颜色
        g.setPaint(CONNECTION_COLOR);

        // 根据连接线类型设置不同的笔划样式
        if (connectionType.equals("association")) {
            g.setStroke(ASSOCIATION_STROKE);
        } else if (highLighted) {
            // 设置线的颜色
            // 设置高亮的连接线颜色和样式
            g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR);
            g.setStroke(HIGHLIGHT_FLOW_STROKE);
        }

        // 遍历点数组，绘制连接线
        for (int i = 1; i < xPoints.length; i++) {
            Integer sourceX = xPoints[i - 1];
            Integer sourceY = yPoints[i - 1];
            Integer targetX = xPoints[i];
            Integer targetY = yPoints[i];
            Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
            g.draw(line);
        }

        // 如果是默认流，绘制默认流的指示器
        if (isDefault) {
            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
            drawDefaultSequenceFlowIndicator(line, scaleFactor);
        }

        // 如果是条件流，绘制条件流的指示器
        if (conditional) {
            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
            drawConditionalSequenceFlowIndicator(line, scaleFactor);
        }

        // 根据关联方向绘制箭头
        if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
            Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
            drawArrowHead(line, scaleFactor);
        }

        // 检查关联方向是否为双向
        if (associationDirection == AssociationDirection.BOTH) {
            // 如果是双向关联，在另一端也绘制箭头
            // 创建一个从箭头到起点的线段，用于计算另一端的箭头位置
            Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
            drawArrowHead(line, scaleFactor);
        }
        // 恢复原始的画笔和笔划样式
        g.setPaint(originalPaint);
        g.setStroke(originalStroke);
    }

    /**
     * 高亮节点设置
     * 绘制高亮区域
     *
     * 此方法用于在图形界面中绘制高亮显示的圆角矩形主要用于突出显示某个区域或元素
     * 它首先保存当前的画笔和笔划样式，然后设置新的画笔颜色和笔划样式以绘制高亮矩形，
     * 绘制完成后恢复原先的画笔和笔划样式这样可以确保绘制高亮效果而不会影响后续的绘制操作
     *
     * @param x 指定绘制高亮区域的起始X坐标
     * @param y 指定绘制高亮区域的起始Y坐标
     * @param width 指定绘制高亮区域的宽度
     * @param height 指定绘制高亮区域的高度
     */
    public void drawHighLight(int x, int y, int width, int height) {
        // 保存原始画笔和笔划样式
        Paint originalPaint = g.getPaint();
        Stroke originalStroke = g.getStroke();
        // 设置高亮节点的颜色
        g.setPaint(HIGHLIGHT_COLOR);
        // 设置较粗的边框笔划样式
        g.setStroke(THICK_TASK_BORDER_STROKE);

        // 创建一个圆角矩形对象
        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
        // 使用当前画笔和笔划样式绘制圆角矩形
        g.draw(rect);

        // 恢复原始画笔和笔划样式
        g.setPaint(originalPaint);
        g.setStroke(originalStroke);
    }

    /**
     * 高亮节点红色
     * 绘制高亮矩形框，用于突出显示指定区域
     * 该方法首先保存原始的画笔和笔划样式，然后设置新的颜色和笔划样式来绘制高亮矩形，
     * 最后恢复原始的画笔和笔划样式这样做是为了确保高亮绘制不会影响后续的绘制操作
     *
     * @param x       矩形左上角的x坐标
     * @param y       矩形左上角的y坐标
     * @param width   矩形的宽度
     * @param height  矩形的高度
     */
    public void drawHighLightRed(int x, int y, int width, int height) {
        // 保存原始的画笔和笔划样式
        Paint originalPaint = g.getPaint();
        Stroke originalStroke = g.getStroke();

        // 设置高亮节点的颜色
        g.setPaint(Color.green);
        // 设置较粗的笔划样式，用于突出显示
        g.setStroke(THICK_TASK_BORDER_STROKE);

        // 创建圆角矩形路径
        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
        // 绘制圆角矩形路径
        g.draw(rect);

        // 恢复原始的画笔和笔划样式，确保后续绘制不受影响
        g.setPaint(originalPaint);
        g.setStroke(originalStroke);
    }

}
